<script lang="tsx">
import type { DescriptionProps, DescInstance, DescItem } from './typing';
import type { DescriptionsProps } from 'ant-design-vue/es/descriptions/index';
import type { CSSProperties } from 'vue';
import type { CollapseContainerOptions } from '../../Container/index';
import { defineComponent, computed, ref, unref, toRefs } from 'vue';
import { get } from 'lodash-es';
import { Descriptions } from 'ant-design-vue';
import { CollapseContainer } from '../../Container/index';
import { useDesign } from '@/hooks/web/useDesign';
import { isFunction } from '@/utils/is';
import { getSlot } from '@/utils/helper/tsxHelper';
import { useAttrs } from '@/hooks/core/useAttrs';

const props = {
	useCollapse: { type: Boolean, default: true },
	title: { type: String, default: '' },
	size: {
		type: String,
		validator: v => ['small', 'default', 'middle', undefined].includes(v),
		default: 'small',
	},
	bordered: { type: Boolean, default: true },
	column: {
		type: [Number, Object] as PropType<number | Recordable>,
		default: () => {
			return { xxl: 4, xl: 3, lg: 3, md: 3, sm: 2, xs: 1 };
		},
	},
	collapseOptions: {
		type: Object as PropType<CollapseContainerOptions>,
		default: null,
	},
	schema: {
		type: Array as PropType<DescItem[]>,
		default: () => [],
	},
	data: { type: Object },
};

export default defineComponent({
	name: 'Description',
	props,
	emits: ['register'],
	setup(props, { slots, emit }) {
		const propsRef = ref<Partial<DescriptionProps> | null>(null);

		const { prefixCls } = useDesign('description');
		const attrs = useAttrs();

		// Custom title component: get title
		const getMergeProps = computed(() => {
			return {
				...props,
				...(unref(propsRef) as Recordable),
			} as DescriptionProps;
		});

		const getProps = computed(() => {
			const opt = {
				...unref(getMergeProps),
				title: undefined,
			};
			return opt as DescriptionProps;
		});

		/**
		 * @description: Whether to setting title
		 */
		const useWrapper = computed(() => !!unref(getMergeProps).title);

		/**
		 * @description: Get configuration Collapse
		 */
		const getCollapseOptions = computed((): CollapseContainerOptions => {
			return {
				// Cannot be expanded by default
				canExpand: false,
				...unref(getProps).collapseOptions,
			};
		});

		const getDescriptionsProps = computed(() => {
			return { ...unref(attrs), ...unref(getProps) } as DescriptionsProps;
		});

		/**
		 * @description:设置desc
		 */
		function setDescProps(descProps: Partial<DescriptionProps>): void {
			// Keep the last setDrawerProps
			propsRef.value = { ...(unref(propsRef) as Recordable), ...descProps } as Recordable;
		}

		// Prevent line breaks
		function renderLabel({ label, labelMinWidth, labelStyle }: DescItem) {
			if (!labelStyle && !labelMinWidth) {
				return label;
			}

			const labelStyles: CSSProperties = {
				...labelStyle,
				minWidth: `${labelMinWidth}px `,
			};
			return <div style={labelStyles}>{label}</div>;
		}

		function renderItem() {
			const { schema, data } = unref(getProps);
			return unref(schema)
				.map(item => {
					const { render, field, span, show, contentMinWidth } = item;

					if (show && isFunction(show) && !show(data)) {
						return null;
					}

					const getContent = () => {
						const _data = unref(getProps)?.data;
						if (!_data) {
							return null;
						}
						const getField = get(_data, field);
						if (getField && !toRefs(_data).hasOwnProperty(field)) {
							return isFunction(render) ? render('', _data) : '';
						}
						return isFunction(render) ? render(getField, _data) : getField ?? '';
					};

					const width = contentMinWidth;
					return (
						<Descriptions.Item label={renderLabel(item)} key={field} span={span}>
							{() => {
								if (!contentMinWidth) {
									return getContent();
								}
								const style: CSSProperties = {
									minWidth: `${width}px`,
								};
								return <div style={style}>{getContent()}</div>;
							}}
						</Descriptions.Item>
					);
				})
				.filter(item => !!item);
		}

		const renderDesc = () => {
			return (
				<Descriptions class={`${prefixCls}`} {...(unref(getDescriptionsProps) as any)}>
					{renderItem()}
				</Descriptions>
			);
		};

		const renderContainer = () => {
			const content = props.useCollapse ? renderDesc() : <div>{renderDesc()}</div>;
			// Reduce the dom level
			if (!props.useCollapse) {
				return content;
			}

			const { canExpand, helpMessage } = unref(getCollapseOptions);
			const { title } = unref(getMergeProps);

			return (
				<CollapseContainer title={title} canExpan={canExpand} helpMessage={helpMessage}>
					{{
						default: () => content,
						action: () => getSlot(slots, 'action'),
					}}
				</CollapseContainer>
			);
		};

		const methods: DescInstance = {
			setDescProps,
		};

		emit('register', methods);
		return () => (unref(useWrapper) ? renderContainer() : renderDesc());
	},
});
</script>
